{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5072f85-b264-4470-a61b-e703b06fc7c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# File: roller.ipynb\n",
    "# Code: Claude Code and Codex\n",
    "# Review: Ryoichi Ando (ryoichi.ando@zozo.com)\n",
    "# License: Apache v2.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "509bdf6f-125f-46d9-b99c-79fdd80b3926",
   "metadata": {},
   "outputs": [],
   "source": [
    "from frontend import App\n",
    "\n",
    "# create an app\n",
    "app = App.create(\"roller\")\n",
    "\n",
    "# create a cylinder mesh for rollers\n",
    "r, half_l = 0.15, 0.7\n",
    "V, F = app.mesh.cylinder(r=r, min_x=-half_l, max_x=half_l, n=40)\n",
    "app.asset.add.tri(\"cylinder\", V, F)\n",
    "\n",
    "# create a knot tetrahedral mesh\n",
    "V, F, T = app.mesh.preset(\"knot\").tetrahedralize().normalize()\n",
    "app.asset.add.tet(\"knot\", V, F, T)\n",
    "\n",
    "# create a scene\n",
    "scene = app.scene.create()\n",
    "\n",
    "# add knot object with friction\n",
    "obj = scene.add(\"knot\").scale(0.6).at(0, 0.4, 0).jitter().rotate(270, \"y\")\n",
    "obj.param.set(\"friction\", 0.5)\n",
    "\n",
    "# add invisible floor\n",
    "scene.add.invisible.wall([0, -1, 0], [0, 1, 0])\n",
    "\n",
    "# create two pairs of counter-rotating rollers to flatten the knot\n",
    "half_gap, left, right = 1.1 * r, [], []\n",
    "left.append(scene.add(\"cylinder\").rotate(90, \"y\").at(-half_gap, 0, 0))\n",
    "left.append(scene.add(\"cylinder\").rotate(90, \"y\").at(-half_gap, -2 * half_gap, 0))\n",
    "right.append(scene.add(\"cylinder\").rotate(90, \"y\").at(half_gap, 0, 0))\n",
    "right.append(scene.add(\"cylinder\").rotate(90, \"y\").at(half_gap, -2 * half_gap, 0))\n",
    "\n",
    "# set spinning motion for rollers\n",
    "w = 360.0\n",
    "for obj in left:\n",
    "    obj.pin().spin(axis=[0, 0, -1], angular_velocity=w)\n",
    "for obj in right:\n",
    "    obj.pin().spin(axis=[0, 0, 1], angular_velocity=w)\n",
    "\n",
    "# set directional coloring for all rollers\n",
    "for obj in left + right:\n",
    "    obj.direction_color(1, 0, 0)\n",
    "\n",
    "# set preview options\n",
    "opts = {\n",
    "    \"pin\": False,\n",
    "    \"wireframe\": True,\n",
    "    \"lookat\": [0, -0.25, 0],\n",
    "    \"eyeup\": 0.25,\n",
    "    \"fov\": 55,\n",
    "}\n",
    "\n",
    "# compile the scene and report stats\n",
    "scene = scene.build().report()\n",
    "\n",
    "# preview the initial scene\n",
    "scene.preview(options=opts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bace491d-1f73-4602-a2e0-b89a83fabdda",
   "metadata": {},
   "outputs": [],
   "source": [
    "# create a new session with the compiled scene\n",
    "session = app.session.create(scene)\n",
    "\n",
    "# set session parameters\n",
    "session.param.set(\"frames\", 180)\n",
    "\n",
    "# build this session\n",
    "session = session.build()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5eba74ef-0373-4d8f-98b3-4609ebcb474a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# start the simulation and live-preview the results\n",
    "session.start().preview(options=opts)\n",
    "\n",
    "# also show simulation logs in realtime\n",
    "session.stream()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fdfb20af-5c02-4cfa-850e-89d568594f72",
   "metadata": {},
   "outputs": [],
   "source": [
    "# create an animation from the simulation results\n",
    "session.animate(options=opts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "907a2929-0a51-4b44-8b66-8498284dc259",
   "metadata": {},
   "outputs": [],
   "source": [
    "# export the animation to file\n",
    "session.export.animation()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f4bd160-a8dc-4476-8429-33269b03a037",
   "metadata": {},
   "outputs": [],
   "source": [
    "# this is for CI\n",
    "if app.ci:\n",
    "    assert session.finished()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
